use std::fmt;

/// SysY程序的根节点
#[derive(Debug, Clone)]
pub struct Program {
    pub items: Vec<Item>,
}

/// 顶层元素：全局变量或函数
#[derive(Debug, Clone)]
pub enum Item {
    GlobalVar(GlobalVar),
    Function(Function),
}

/// 全局变量或常量
#[derive(Debug, Clone)]
pub struct GlobalVar {
    pub is_const: bool,
    pub name: String,
    pub init: Option<Expr>,
}

/// 函数定义
#[derive(Debug, Clone)]
pub struct Function {
    pub name: String,
    pub ret_type: Type,
    pub params: Vec<Parameter>,
    pub body: Block,
}

/// 函数参数
#[derive(Debug, Clone)]
pub struct Parameter {
    pub name: String,
    pub ty: Type,
}

/// 基本类型
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Type {
    Int,
    Void,
}

impl fmt::Display for Type {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Type::Int => f.write_str("int"),
            Type::Void => f.write_str("void"),
        }
    }
}

/// 代码块
#[derive(Debug, Clone)]
pub struct Block {
    pub stmts: Vec<Stmt>,
}

/// 语句
#[derive(Debug, Clone)]
pub enum Stmt {
    VarDecl {
        is_const: bool,
        name: String,
        init: Option<Expr>,
    },
    Assign {
        name: String,
        expr: Expr,
    },
    Expr(Expr),
    If {
        cond: Expr,
        then_branch: Box<Stmt>,
        else_branch: Option<Box<Stmt>>,
    },
    While {
        cond: Expr,
        body: Box<Stmt>,
    },
    Break,
    Continue,
    Return(Option<Expr>),
    Block(Block),
}

/// 表达式
#[derive(Debug, Clone)]
pub enum Expr {
    Int(i32),
    Variable(String),
    Binary {
        op: BinaryOp,
        lhs: Box<Expr>,
        rhs: Box<Expr>,
    },
    Unary {
        op: UnaryOp,
        expr: Box<Expr>,
    },
    Call {
        name: String,
        args: Vec<Expr>,
    },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Lt,
    Le,
    Gt,
    Ge,
    Eq,
    Ne,
    And,
    Or,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
    Pos,
    Neg,
    Not,
}
